/*
 * @Author: 0x9DEFA478
 * @Date: 2024-01-13 18:16:26
 * @LastEditTime: 2024-04-18 20:45:54
 * @LastEditors: 0x9DEFA478
 * @Description: 指针对象定义
 *               指针必须是通过new产生(或者等效的方式)，能够调用delete
 *               多个指针对象能够容纳同一个指针
 *               同时容纳同一个指针必须由H::PointerObject构造、复制实现，否则会出现重复析构的问题
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#ifndef hH_PointerObject_HPP_
#define hH_PointerObject_HPP_
#include "H_Concurrency.hpp"




namespace H{

  template<typename ObjectType,H_Concurrency_is_Lock Lock=Concurrency::EmptyLock>
  class PointerObject{

    public:
      using Type=ObjectType;
      using ConstType=const ObjectType;

      using Pointer=Type*;
      using Reference=Type&;
      using RightReference=Type&&;
      
      using ConstPointer=ConstType*;
      using ConstReference=ConstType&;
      using ConstRightReference=ConstType&&;


    public:
      PointerObject(Pointer objectPointer=nullptr,bool IsArray=false,usize Length=1):referenceRecorder(new ReferenceRecorder(objectPointer,IsArray,Length)){}
      ~PointerObject(){
        if(referenceRecorder->Decrease()){
          delete referenceRecorder;
        }
      }
      static PointerObject Array(usize Length){
        if(Length==0){
          return PointerObject(nullptr,true);
        }
        return PointerObject(new Type[Length],true,Length);
      }

      PointerObject(const PointerObject& pointerObject){
        referenceRecorder=&pointerObject.referenceRecorder->Increase();
      }

      PointerObject& operator=(const PointerObject& pointerObject){
        if(referenceRecorder==pointerObject.referenceRecorder){
          return *this;
        }
        if(referenceRecorder->Decrease()){
          delete referenceRecorder;
        }
        referenceRecorder=&pointerObject.referenceRecorder->Increase();
        return *this;
      }
      PointerObject& operator=(const PointerObject&& pointerObject){
        if(referenceRecorder==pointerObject.referenceRecorder){
          return *this;
        }
        if(referenceRecorder->Decrease()){
          delete referenceRecorder;
        }
        referenceRecorder=&pointerObject.referenceRecorder->Increase();
        return *this;
      }


      operator Pointer(){return *referenceRecorder;}
      operator ConstPointer()const{return *referenceRecorder;}

      operator bool()const{return static_cast<ConstPointer>(*referenceRecorder)!=nullptr;}

      bool operator!()const{return static_cast<ConstPointer>(*referenceRecorder)==nullptr;}
      bool operator==(ConstPointer objectPointer)const{return static_cast<ConstPointer>(*referenceRecorder)==objectPointer;}
      bool operator==(const PointerObject& pointerObject)const{return referenceRecorder==pointerObject.referenceRecorder;}
      bool operator==(const PointerObject&& pointerObject)const{return referenceRecorder==pointerObject.referenceRecorder;}
      bool operator!=(ConstPointer objectPointer)const{return static_cast<ConstPointer>(*referenceRecorder)!=objectPointer;}
      bool operator!=(const PointerObject& pointerObject)const{return referenceRecorder!=pointerObject.referenceRecorder;}
      bool operator!=(const PointerObject&& pointerObject)const{return referenceRecorder!=pointerObject.referenceRecorder;}

      Reference operator*(){return **referenceRecorder;}
      ConstReference operator*()const{return **referenceRecorder;}

      Pointer operator->(){return *referenceRecorder;}
      ConstPointer operator->()const{return *referenceRecorder;}

      Reference operator[](auto Index){return (*referenceRecorder)[Index];}
      ConstReference operator[](auto Index)const{return (*referenceRecorder)[Index];}

      usize Length()const{return referenceRecorder->Length();}
      PointerObject Clone()const{
        if((*referenceRecorder)==nullptr){
          return nullptr;
        }
        usize length=Length();
        auto r=Array(length);
        for(usize i=0U;i<length;i++){
          r[i]=(*this)[i];
        }
        return r;
      }

    private:
      class ReferenceRecorder{

        public:
          ReferenceRecorder(Pointer objectPointer,bool IsArray,usize Length):objectPointer(objectPointer),length(Length),referenceCount(0),isArray(IsArray){}
          ~ReferenceRecorder(){
            if(objectPointer!=nullptr){
              if(isArray){
                delete[] objectPointer;
              }else{
                delete objectPointer;
              }
            }
          }
          ReferenceRecorder(const ReferenceRecorder&)=delete;

          operator Pointer(){return objectPointer;}
          operator ConstPointer()const{return objectPointer;}

          Reference operator*(){return *objectPointer;}
          ConstReference operator*()const{return *objectPointer;}

          Pointer operator->(){return objectPointer;}
          ConstPointer operator->()const{return objectPointer;}

          Reference operator[](auto Index){return objectPointer[Index];}
          ConstReference operator[](auto Index)const{return objectPointer[Index];}

          usize Length()const{return (objectPointer==nullptr)?0:length;}

          ReferenceRecorder& Increase(){
            lock.lock();
            referenceCount++;
            lock.unlock();
            return *this;
          }
          bool Decrease(){
            bool r;

            r=true;
            lock.lock();
            if(referenceCount>0){
              referenceCount--;
              r=false;
            }
            lock.unlock();
            return r;
          }
        private:
          Pointer objectPointer;
          usize length;
          Lock lock;
          usize referenceCount;
          bool isArray;

      };

    private:
      ReferenceRecorder* referenceRecorder;
  };

}




#endif //hH_PointerObject_HPP_
